// 我们可以通过type可以用来声明一个对象类型
type Point = {
    x: number,
    y: number
}

// 对象另一种声明方式就是通过接口来声明
interface Point2 {
    x: number,
    y: number
}

//接口和type类似可以定义可选属性
interface Person {
    name: string,
    age?: number,
    friend?: {
        name: string
    }
}
const person: Person = {
    name: "why",
    age: 19,
    friend: {
        name: "kobe"
    }
}

console.log(person.name);
console.log(person.friend?.name);

// 接口也和类 类似 可以定义只读属性
interface Person2 {
    readonly name: string
    age?: number
    readonly friend?: {
        name: string
    }
}

const person2: Person2 = {
    name: "why",
    age: 28,
    friend: {
        name: "kobe"
    }
}
//person2.name = "coderwhy"不可以设置
//person.friend = {}//不可以设置,因为修改了对象的引用地址

if (person2.friend) {
    person2.friend.name = "123" //修改属性没有修改friend对象的地址,固可执行
}


// interface来定义对象类型,之前属性名,类型,方法都是确定的,但有时候我们会遇到类似下面的对象,就是索引不确定的情况
interface FrontLanguage {
    [index: number]: string
}

const frontend: FrontLanguage = {
    1: 'HTML',
    2: 'CSS',
    3: 'JavaScript'
}
const frontend2: FrontLanguage = {
    1: 'HTML',
    2: 'CSS',
    3: 'JavaScript',
    4: 'TypeScript' //只要属性符合index:number这个规则都可以添加
}
interface LanguageBirth {
    [name: string]: number  //这是不确定的属性,只要符合是字符串类型的属性都是name属性
    Java: number    //这是确定的属性
}
const language: LanguageBirth = {
    "JavaScript": 1996,
    "C": 1972,
    "Java": 1995   //这个属性必须要要有
}



// 前面都是通过interface来定义对象中的属性和方法,实际上
// 接口还可以定义函数类型
interface CalcFunc {
    (num1: number, num2: number): number
}
const add: CalcFunc = (num1, num2) => {
    return num1+num2
}
const sub: CalcFunc = (num1, num2) => {
    return num1-num2
}
// 不过推荐使用类型别名来定义函数
type CalcFunc2 = (num1: number, num2: number) => number
const add2: CalcFunc = (num1, num2) => {
    return num1+num2
}
const sub2: CalcFunc = (num1, num2) => {
    return num1-num2
}